from inspect import trace
import threading
import time
import datetime 
from config import fieldName, makeNewSession, INTERVAL, calc_space, UPLOADDIR,debug
import config
import models
from sqlalchemy import  and_, or_
import traceback
import json
from API.messageAPI import send_message_to, sendMaster, upload_group_file
from API.yqpost import Yqpost
import os
from random import randint

class Timer:
    

    
    @staticmethod
    def dict2string(dict_msg:dict) -> str:
        msg = ''
        for k in dict_msg:
            v = str(dict_msg[k])
            if len(v) > 8:
                msg += f"{k}:\n{v}\n"
            else:
                msg += f"{k}: {v}\n"

    # 解析task type 做对应的处理
    def parse_task(self, task_list, r_msg, session):
        for task in task_list:
            if task["type"] == "message":
                self.sendMsg(task, r_msg, session)
            elif task["type"] == "yqpost":
                if task["message_type"] == "groups":
                    yq = Yqpost()
                    for cls in task["cls_group"]:
                        msg = yq.check_report_banji_and_gen_msg(cls, task["cls_group"][cls], session)
                        send_message_to("group", task["cls_group"][cls], msg)
                        time.sleep(randint(5,30)*0.1)


    # 执行到期的timer
    def do_task(self, timerID , title, task_list):
        debug("执行 task", timerID, title, task_list)
        if isinstance(task_list, str):
            task_list = json.loads(task_list)
        st = time.time()
        r_msg = {
            "timerID":timerID,
            "title": title,
            "datetime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        }
        session = makeNewSession()
        try:
            self.parse_task(task_list, r_msg, session)
            r_msg["time_cost"] =f"{round(time.time() - st,5)}s"
            msg = self.dict2string(r_msg)
            sendMaster(msg)
        except:
            traceback.print_exc()
            session.rollback()
        session.query(models.Timer).filter(models.Timer.timerID==timerID).update({models.Timer.log:json.dumps(r_msg, ensure_ascii=False, indent='\t')})
        session.commit()
        session.close()


    def check_time(self):
        debug("enter check_time")
        t_day = None
        while True:
            debug("do check_time loop")
            dt = datetime.datetime.now()
            session = makeNewSession()
            t_now = int(dt.timestamp())
            try:
                # 修改匹配今日的任务 cmp_time 日期字段为今天
                if t_day == None or t_day != dt.day:
                    t_day = dt.day
                    t_date = dt.strftime("%Y-%m-%d")
                    t_week = dt.weekday()
                    debug("enter day update data", t_day, t_date, t_week)
                    
                    timers = session.query(models.Timer).filter(or_(models.Timer.date==t_date, models.Timer.week>=f"{'0'*t_week}1{'0'*(6-t_week)}"))
                    flag = False
                    for timer in timers:
                        if timer.week[t_week] == '1' or timer.date == t_date:
                            timer.cmp_time = int(datetime.datetime.strptime(f'{t_date} {timer.time}', '%Y-%m-%d %H:%M:%S').timestamp())
                            timer.exc_count=0
                            flag = True
                    if flag: session.commit()



                # 查找并执行 可以执行的timer任务
                time_interval = t_now+INTERVAL
                timers = list(session.query(models.Timer).filter(
                    
                    models.Timer.use_flag == True,
                    or_(
                        and_(
                            models.Timer.cmp_time >= t_now, 
                            models.Timer.cmp_time <= time_interval, 
                            models.Timer.exc_count == 0
                        ),
                        models.Timer.date == "soon"
                        )
                    ))
                config.TIMER_NO_CHANGE=True
                new_timer = timers[:]
                while True:
                    t_now = int(time.time())
                    if time_interval >= t_now and config.TIMER_NO_CHANGE:
                        # print("t_now", t_now, time_interval,  config.TIMER_NO_CHANGE)
                        ch_flag = False
                        for timer in timers:
                            debug("获得timer",timer.timerID, timer.title)
                            # 执行
                            if timer.cmp_time <= t_now and timer.exc_count == 0:
                                tasks = threading.Thread(target=self.do_task, args=(timer.timerID, timer.title, timer.task_list))
                                tasks.start()
                                

                                # 执行计数+1
                                timer.exc_count += 1
                                # 日期过期， 且没有每周字段， 删除计时器任务
                                if timer.week == "0000000":
                                    session.delete(timer)

                                session.commit()
                                ch_flag = True
                                new_timer.remove(timer)
                        if ch_flag: 
                            timers = new_timer[:]

                        time.sleep(1)
                    else:
                        print("timer flush")
                        break
                
            except:
                traceback.print_exc()
            session.close()
            # time.sleep(INTERVAL)


    # 发送消息模块
    @staticmethod
    def sendMsg(task:dict, r_msg, session):
        if task["message_type"] == "private":
            if task["f_msg"]:
                msg = f"{task['message']}\n附件\n{task['f_msg']}"
            else:
                msg = task["message"]
            err_list = []
            for id_ in task["message_list"]:
                time.sleep(randint(1,10)*0.1)
                try:flag = send_message_to("private", id_, msg)
                except:flag=False
                if not flag:
                    err_list.append(id_)
            if err_list:
                r_msg["private"] = f"{len(err_list)}条私聊消息发送失败:\n"
                qs = session.query(models.Student).filter(models.Student.QQ.in_(err_list)).all()
                for q in qs:
                    r_msg["private"] += f"{q.uid}{calc_space(13, len(str(q.uid)),space=' ')}{q.name}{calc_space(5,len(q.name))}{q.QQ}\n"
            else:
                r_msg["private"] = f"发送成功,共{len(task['message_list'])}人"

        elif task["message_type"] == "groups":
            msg = task['message']
            err_list = []

            for id_ in task["message_list"]:
                fqs = session.query(models.File).filter(models.File.fileID.in_(task["files"])).all()
                for fq in fqs:
                    upload_group_file(id_, os.path.join(UPLOADDIR, fq.serverFileName), fq.userFileName, f"/{fieldName(r_msg['title'])}")
                    time.sleep(randint(1,10)*0.1)
                time.sleep(randint(1,10)*0.1)
                try:flag = send_message_to("group", id_, msg)
                except:flag=False
                if not flag:
                    err_list.append(id_)
            if err_list:
                r_msg["groups"] = f"{len(err_list)}条群消息发送失败:\n"
                qs = session.query(models.Classes).filter(models.Classes.mainGroup.in_(err_list)).all()
                for q in qs:
                    r_msg["groups"] += f"{q.classesID}{calc_space(13, len(str(q.q.classesID)),space=' ')}{q.mainGroup}\n"
            else:
                r_msg["groups"] = f"发送成功,共{len(task['message_list'])}条"
    
    @staticmethod
    def genTimer(title, weeks, time_day, time, task_list):
        week=['0','0','0','0','0','0','0']
        for w in weeks:
            week[w]='1'
        dt = datetime.datetime.now()
        t_date = dt.strftime("%Y-%m-%d")
        if dt.weekday() in weeks or t_date==time_day:
            cmp_time = datetime.datetime.strptime(f"{t_date} {time}",  '%Y-%m-%d %H:%M:%S').timestamp()
        else: 
            cmp_time = 0
        timer = models.Timer(
            title=title,
            func_type="message",
            week=''.join(week),
            date=time_day,
            time=time,
            cmp_time=cmp_time,
            use_flag=True,
            task_list=json.dumps(task_list, ensure_ascii=False, indent='\t')
        )
        config.TIMER_NO_CHANGE = False  
        return timer
        # session.add(timer)


    def timer_start(self):
        t = threading.Thread(target=self.check_time)
        t.start()
        
    